package com.platform.module.common.utils;

import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class IPUtils {
    private static final Logger log = LoggerFactory.getLogger(IPUtils.class);
    public static final String _255 = "(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
    public static final Pattern pattern = Pattern.compile("^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");

    public static String longToIpV4(long longIp) {
        int octet3 = (int) ((longIp >> 24) % 256L);
        int octet2 = (int) ((longIp >> 16) % 256L);
        int octet1 = (int) ((longIp >> 8) % 256L);
        int octet0 = (int) (longIp % 256L);
        return octet3 + "." + octet2 + "." + octet1 + "." + octet0;
    }

    public static long ipV4ToLong(String ip) {
        String[] octets = ip.split("\\.");
        return (Long.parseLong(octets[0]) << 24) + ((long) Integer.parseInt(octets[1]) << 16) + ((long) Integer.parseInt(octets[2]) << 8) + (long) Integer.parseInt(octets[3]);
    }

    public static boolean isIPv4Private(String ip) {
        long longIp = ipV4ToLong(ip);
        return longIp >= ipV4ToLong("10.0.0.0") && longIp <= ipV4ToLong("10.255.255.255")
                || longIp >= ipV4ToLong("172.16.0.0") && longIp <= ipV4ToLong("172.31.255.255")
                || longIp >= ipV4ToLong("192.168.0.0") && longIp <= ipV4ToLong("192.168.255.255");
    }

    public static boolean isIPv4Valid(String ip) {
        return ip != null && pattern.matcher(ip).matches();
    }

    public static String getIpFromRequest(HttpServletRequest request) {
        boolean found = false;
        String xForwardedFor = request.getHeader("x-forwarded-for");
        log.info("xForwardedFor={}", xForwardedFor);
        String ip;
        if ((ip = request.getHeader("x-forwarded-for")) != null) {
            StringTokenizer tokenizer = new StringTokenizer(ip, ",");
            while (tokenizer.hasMoreTokens()) {
                ip = tokenizer.nextToken().trim();
                if (isIPv4Valid(ip) && !isIPv4Private(ip)) {
                    found = true;
                    break;
                }
            }
        }

        if (!found) {
            ip = request.getRemoteAddr();
        }

        if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
            InetAddress inet = null;

            try {
                inet = InetAddress.getLocalHost();
            } catch (UnknownHostException var6) {
                var6.printStackTrace();
            }

            ip = inet.getHostAddress();
        }

        if (ip != null && ip.length() > 15 && ip.indexOf(",") > 0) {
            ip = ip.substring(0, ip.indexOf(","));
        }

        return ip;
    }

    public static String getIpV6FromRequest(HttpServletRequest request) {
        String ip = "";

        try {
            boolean found = false;
            if ((ip = request.getHeader("x-forwarded-for")) != null) {
                StringTokenizer tokenizer = new StringTokenizer(ip, ",");
                while (tokenizer.hasMoreTokens()) {
                    ip = tokenizer.nextToken().trim();

                    try {
                        InetAddress inetAddress = InetAddress.getByName(ip);
                        if (inetAddress instanceof Inet6Address || (isIPv4Valid(ip) && !isIPv4Private(ip))) {
                            found = true;
                            break;
                        }
                    } catch (UnknownHostException ignored) {
                    }
                }
            }

            if (!found) {
                ip = request.getRemoteAddr();
            }

            if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
                InetAddress inet = null;

                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException var5) {
                    var5.printStackTrace();
                }

                ip = inet.getHostAddress();
            }

            if (ip != null && ip.length() > 15 && ip.indexOf(",") > 0) {
                ip = ip.substring(0, ip.indexOf(","));
            }
        } catch (Exception var7) {
            log.error("异常信息", var7);
        }

        return ip;
    }

    public static boolean isIPV4(String addr) {
        if (addr.length() >= 7 && addr.length() <= 15) {
            String rexp = "([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}";
            Pattern pat = Pattern.compile(rexp);
            Matcher mat = pat.matcher(addr);
            return mat.find();
        } else {
            return false;
        }
    }

    public static boolean isInner(String ip) {
        String reg = "(10|172|192)\\.([0-1][0-9]{0,2}|[2][0-5]{0,2}|[3-9][0-9]{0,1})\\.([0-1][0-9]{0,2}|[2][0-5]{0,2}|[3-9][0-9]{0,1})\\.([0-1][0-9]{0,2}|[2][0-5]{0,2}|[3-9][0-9]{0,1})";
        Pattern p = Pattern.compile(reg);
        Matcher matcher = p.matcher(ip);
        return matcher.find();
    }

    public static boolean isInnerIP(String ipAddress) {
        boolean isInnerIp = false;
        long ipNum = getIpNum(ipAddress);
        long aBegin = getIpNum("10.0.0.0");
        long aEnd = getIpNum("10.255.255.255");
        long bBegin = getIpNum("172.16.0.0");
        long bEnd = getIpNum("172.31.255.255");
        long cBegin = getIpNum("192.168.0.0");
        long cEnd = getIpNum("192.168.255.255");
        isInnerIp = isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || ipAddress.equals("127.0.0.1");
        return isInnerIp;
    }

    private static long getIpNum(String ipAddress) {
        String[] ip = ipAddress.split("\\.");
        long a = Integer.parseInt(ip[0]);
        long b = Integer.parseInt(ip[1]);
        long c = Integer.parseInt(ip[2]);
        long d = Integer.parseInt(ip[3]);
        return a * 256L * 256L * 256L + b * 256L * 256L + c * 256L + d;
    }

    private static boolean isInner(long userIp, long begin, long end) {
        return userIp >= begin && userIp <= end;
    }

}
